home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1995 October / EnigmA AMIGA RUN 01 (1995)(G.R. Edizioni)(IT)[!][issue 1995-10][Aminet 7].iso / Aminet / comm / tcp / AmigaTCP.lha / AmigaTCP / src / telnet.c < prev    next >
C/C++ Source or Header  |  1989-06-24  |  8KB  |  439 lines

  1. #include <stdio.h>
  2. #include "machdep.h"
  3. #include "mbuf.h"
  4. #include "timer.h"
  5. #include "internet.h"
  6. #include "icmp.h"
  7. #include "netuser.h"
  8. #include "tcp.h"
  9. #include "telnet.h"
  10. #include "session.h"
  11.  
  12. extern char nospace[];
  13. int refuse_echo = 0;
  14. int unix_line_mode = 0;    /* if true turn <cr> to <nl> when in line mode */
  15.  
  16. #ifdef    DEBUG
  17. char *t_options[] = {
  18.     "Transmit Binary",
  19.     "Echo",
  20.     "",
  21.     "Suppress Go Ahead",
  22.     "",
  23.     "Status",
  24.     "Timing Mark"
  25. };
  26. #endif
  27.  
  28. /* Execute user telnet command */
  29. int
  30. dotelnet(argc,argv)
  31. int argc;
  32. char *argv[];
  33. {
  34.     void t_state(),rcv_char();
  35.     char *inet_ntoa(),*calloc();
  36.     int32 aton();
  37.     int send_tel();
  38.         int unix_send_tel();
  39.     struct session *s,*newsession();
  40.     struct telnet *tn;
  41.     struct tcb *tcb;
  42.     struct socket lsocket,fsocket;
  43.  
  44.  
  45.     lsocket.address = ip_addr;
  46.     lsocket.port = lport++;
  47.     fsocket.address = aton(argv[1]);
  48.     if(argc < 3)
  49.         fsocket.port = TELNET_PORT;
  50.     else
  51.         fsocket.port = atoi(argv[2]);
  52.  
  53.     /* Allocate a session descriptor */
  54.     if((s = newsession()) == NULLSESSION){
  55.         printf("Too many sessions\r\n");
  56.         return 1;
  57.     }
  58.     s->type = TELNET;
  59.     if ((refuse_echo == 0) && (unix_line_mode != 0)) {
  60.         s->parse = unix_send_tel;
  61.     } else {
  62.         s->parse = send_tel;
  63.     }
  64.     current = s;
  65.  
  66.     /* Create and initialize a Telnet protocol descriptor */
  67.     if((tn = (struct telnet *)calloc(1,sizeof(struct telnet))) == NULLTN){
  68.         printf(nospace);
  69.         s->type = FREE;
  70.         return 1;
  71.     }
  72.     tn->session = s;    /* Upward pointer */
  73.     tn->state = TS_DATA;
  74.     s->cb.telnet = tn;    /* Downward pointer */
  75.  
  76.     tcb = open_tcp(&lsocket,&fsocket,TCP_ACTIVE,0,
  77.      rcv_char,NULLVFP,t_state,0,(int *)tn);
  78.     if(tcb == NULLTCB || tcb->state == CLOSED){
  79.         /* This is actually a bit dirty here. About the only time the
  80.          * state will be closed here is if we tried to connect to
  81.          * ourselves and got RST'ed.  If this is true then the close
  82.          * upcall will already have freed the TCB and telnet block,
  83.          * so we're looking at the TCB after it's back on the heap.
  84.          */
  85.         return 0;
  86.     }
  87.     tn->tcb = tcb;    /* Downward pointer */
  88.     go();
  89.     return 0;
  90. }
  91.  
  92. /* Process typed characters */
  93. int
  94. unix_send_tel(buf,n)
  95. char *buf;
  96. int16 n;
  97. {
  98.     int i;
  99.  
  100.     for (i=0; (i<n) && (buf[i] != '\r'); i++)
  101.         ;
  102.     if (buf[i] == '\r') {
  103.         buf[i] = '\n';
  104.         n = i+1;
  105.     }
  106.     send_tel(buf,n);
  107. }
  108. int
  109. send_tel(buf,n)
  110. char *buf;
  111. int16 n;
  112. {
  113.     struct mbuf *bp,*qdata();
  114.     if(current == NULLSESSION || current->cb.telnet == NULLTN
  115.      || current->cb.telnet->tcb == NULLTCB)
  116.         return;
  117.     bp = qdata(buf,n);
  118.     send_tcp(current->cb.telnet->tcb,bp);
  119. }
  120.  
  121. /* Process incoming TELNET characters */
  122. int
  123. tel_input(tn,bp)
  124. register struct telnet *tn;
  125. struct mbuf *bp;
  126. {
  127.     char c;
  128.     int ci;
  129.     void doopt(),dontopt(),willopt(),wontopt(),answer();
  130. #ifdef    FAST    /* DON'T USE -- Aztec memchr() routine is broken */
  131.     char *memchr();
  132.  
  133.     /* Optimization for very common special case -- no command chars */
  134.     if(tn->state == TS_DATA){
  135.         while(bp != NULLBUF && memchr(bp->data,IAC,bp->cnt) == NULLCHAR){
  136.             fflush(stdout);
  137.             write(1,bp->data,bp->cnt);
  138.             bp = free_mbuf(bp);
  139.         }
  140.     }
  141. #endif
  142.     while(pullup(&bp,&c,1) == 1){
  143.         ci = c & 0xff;
  144.         switch(tn->state){
  145.         case TS_DATA:
  146.             if(ci == IAC){
  147.                 tn->state = TS_IAC;
  148.             } else {
  149.                 if(!tn->remote[TN_TRANSMIT_BINARY])
  150.                     c &= 0x7f;
  151.                 putchar(c);
  152.             }
  153.             break;
  154.         case TS_IAC:
  155.             switch(ci){
  156.             case WILL:
  157.                 tn->state = TS_WILL;
  158.                 break;
  159.             case WONT:
  160.                 tn->state = TS_WONT;
  161.                 break;
  162.             case DO:
  163.                 tn->state = TS_DO;
  164.                 break;
  165.             case DONT:
  166.                 tn->state = TS_DONT;
  167.                 break;
  168.             case IAC:
  169.                 putchar(c);
  170.                 tn->state = TS_DATA;
  171.                 break;
  172.             default:
  173.                 tn->state = TS_DATA;
  174.                 break;
  175.             }
  176.             break;
  177.         case TS_WILL:
  178.             willopt(tn,ci);
  179.             tn->state = TS_DATA;
  180.             break;
  181.         case TS_WONT:
  182.             wontopt(tn,ci);
  183.             tn->state = TS_DATA;
  184.             break;
  185.         case TS_DO:
  186.             doopt(tn,ci);
  187.             tn->state = TS_DATA;
  188.             break;
  189.         case TS_DONT:
  190.             dontopt(tn,ci);
  191.             tn->state = TS_DATA;
  192.             break;
  193.         }
  194.     }
  195. }
  196.  
  197. /* Telnet receiver upcall routine */
  198. void
  199. rcv_char(tcb,cnt)
  200. register struct tcb *tcb;
  201. int16 cnt;
  202. {
  203.     struct mbuf *bp;
  204.     struct telnet *tn;
  205.  
  206.     if((tn = (struct telnet *)tcb->user) == NULLTN){
  207.         /* Unknown connection; ignore it */
  208.         return;
  209.     }
  210.     /* Hold output if we're not the current session */
  211.     if(mode != CONV_MODE || current == NULLSESSION || current->cb.telnet != tn)
  212.         return;
  213.  
  214.     if(recv_tcp(tcb,&bp,cnt) > 0)
  215.         tel_input(tn,bp);
  216.  
  217.     fflush(stdout);
  218. }
  219.  
  220. /* State change upcall routine */
  221. void
  222. t_state(tcb,old,new)
  223. register struct tcb *tcb;
  224. char old,new;
  225. {
  226.     struct telnet *tn;
  227.     char notify = 0;
  228.     extern char *tcpstates[];
  229.     extern char *reasons[];
  230.     extern char *unreach[];
  231.     extern char *exceed[];
  232.  
  233.     /* Can't add a check for unknown connection here, it would loop
  234.      * on a close upcall! We're just careful later on.
  235.      */
  236.     tn = (struct telnet *)tcb->user;
  237.  
  238.     if(current != NULLSESSION && current->type == TELNET && current->cb.telnet == tn)
  239.         notify = 1;
  240.  
  241.     switch(new){
  242.     case CLOSE_WAIT:
  243.         if(notify)
  244.             printf("%s\r\n",tcpstates[new]);
  245.         close_tcp(tcb);
  246.         break;
  247.     case CLOSED:    /* court adjourned */
  248.         if(notify){
  249.             printf("%s (%s",tcpstates[new],reasons[tcb->reason]);
  250.             if(tcb->reason == NETWORK){
  251.                 switch(tcb->type){
  252.                 case DEST_UNREACH:
  253.                     printf(": %s unreachable",unreach[tcb->code]);
  254.                     break;
  255.                 case TIME_EXCEED:
  256.                     printf(": %s time exceeded",exceed[tcb->code]);
  257.                     break;
  258.                 }
  259.             }
  260.             printf(")\r\n");
  261.             cmdmode();
  262.         }
  263.         del_tcp(tcb);
  264.         if(tn != NULLTN)
  265.             free_telnet(tn);
  266.         break;
  267.     default:
  268.         if(notify)
  269.             printf("%s\r\n",tcpstates[new]);
  270.         break;
  271.     }
  272.     fflush(stdout);
  273. }
  274. /* Delete telnet structure */
  275. static
  276. free_telnet(tn)
  277. struct telnet *tn;
  278. {
  279.     if(tn->session != NULLSESSION)
  280.         freesession(tn->session);
  281.  
  282.     if(tn != NULLTN)
  283.         free((char *)tn);
  284. }
  285.  
  286. /* The guts of the actual Telnet protocol: negotiating options */
  287. static
  288. void
  289. willopt(tn,opt)
  290. struct telnet *tn;
  291. int opt;
  292. {
  293.     int ack;
  294.     void answer();
  295.  
  296. #ifdef    DEBUG
  297.     printf("recv: will ");
  298.     if(opt <= NOPTIONS)
  299.         printf("%s\r\n",t_options[opt]);
  300.     else
  301.         printf("%u\r\n",opt);
  302. #endif
  303.     
  304.     switch(opt){
  305.     case TN_TRANSMIT_BINARY:
  306.     case TN_ECHO:
  307.     case TN_SUPPRESS_GA:
  308.         if(tn->remote[opt] == 1)
  309.             return;        /* Already set, ignore to prevent loop */
  310.         if(opt == TN_ECHO){
  311.             if(refuse_echo){
  312.                 /* User doesn't want to accept */
  313.                 ack = DONT;
  314.                 break;
  315.             } else
  316.                 raw();        /* Put tty into raw mode */
  317.         }
  318.         tn->remote[opt] = 1;
  319.         ack = DO;            
  320.         break;
  321.     default:
  322.         ack = DONT;    /* We don't know what he's offering; refuse */
  323.     }
  324.     answer(tn,ack,opt);
  325. }
  326. static
  327. void
  328. wontopt(tn,opt)
  329. struct telnet *tn;
  330. int opt;
  331. {
  332.     void answer();
  333.  
  334. #ifdef    DEBUG
  335.     printf("recv: wont ");
  336.     if(opt <= NOPTIONS)
  337.         printf("%s\r\n",t_options[opt]);
  338.     else
  339.         printf("%u\r\n",opt);
  340. #endif
  341.     if(opt <= NOPTIONS){
  342.         if(tn->remote[opt] == 0)
  343.             return;        /* Already clear, ignore to prevent loop */
  344.         tn->remote[opt] = 0;
  345.         if(opt == TN_ECHO)
  346.             cooked();    /* Put tty into cooked mode */
  347.     }
  348.     answer(tn,DONT,opt);    /* Must always accept */
  349. }
  350. static
  351. void
  352. doopt(tn,opt)
  353. struct telnet *tn;
  354. int opt;
  355. {
  356.     void answer();
  357.     int ack;
  358.  
  359. #ifdef    DEBUG
  360.     printf("recv: do ");
  361.     if(opt <= NOPTIONS)
  362.         printf("%s\r\n",t_options[opt]);
  363.     else
  364.         printf("%u\r\n",opt);
  365. #endif
  366.     switch(opt){
  367. #ifdef    FUTURE    /* Use when local options are implemented */
  368.         if(tn->local[opt] == 1)
  369.             return;        /* Already set, ignore to prevent loop */
  370.         tn->local[opt] = 1;
  371.         ack = WILL;
  372.         break;
  373. #endif
  374.     default:
  375.         ack = WONT;    /* Don't know what it is */
  376.     }
  377.     answer(tn,ack,opt);
  378. }
  379. static
  380. void
  381. dontopt(tn,opt)
  382. struct telnet *tn;
  383. int opt;
  384. {
  385.     void answer();
  386.  
  387. #ifdef    DEBUG
  388.     printf("recv: dont ");
  389.     if(opt <= NOPTIONS)
  390.         printf("%s\r\n",t_options[opt]);
  391.     else
  392.         printf("%u\r\n",opt);
  393. #endif
  394.     if(opt <= NOPTIONS){
  395.         if(tn->local[opt] == 0){
  396.             /* Already clear, ignore to prevent loop */
  397.             return;
  398.         }
  399.         tn->local[opt] = 0;
  400.     }
  401.     answer(tn,WONT,opt);
  402. }
  403. static
  404. void
  405. answer(tn,r1,r2)
  406. struct telnet *tn;
  407. int r1,r2;
  408. {
  409.     struct mbuf *bp,*qdata();
  410.     char s[3];
  411.  
  412. #ifdef    DEBUG
  413.     switch(r1){
  414.     case WILL:
  415.         printf("sent: will ");
  416.         break;
  417.     case WONT:
  418.         printf("sent: wont ");
  419.         break;
  420.     case DO:
  421.         printf("sent: do ");
  422.         break;
  423.     case DONT:
  424.         printf("sent: dont ");
  425.         break;
  426.     }
  427.     if(r2 <= 6)
  428.         printf("%s\r\n",t_options[r2]);
  429.     else
  430.         printf("%u\r\n",r2);
  431. #endif
  432.  
  433.     s[0] = IAC;
  434.     s[1] = r1;
  435.     s[2] = r2;
  436.     bp = qdata(s,(int16)3);
  437.     send_tcp(tn->tcb,bp);
  438. }
  439.